// vue - route 的 封装
import {defineComponent,h,Transition,ref, KeepAlive } from "vue"
import { createMemoryHistory,RouterView, createRouter, RouterOptions,Router as TypeRouter,RouteRecordRaw ,RouteLocationNormalizedGeneric} from 'vue-router'


type HookName = 'before'|'after'

export const UIRouter = defineComponent(() => 
    () => 
        h(RouterView,{},{default:({Component,route}:any) => 
            h(Transition,{name:route.meta.transition || 'fade'},{default:() => 
                Component ? 
                    route.meta.keepalive ? 
                        h(KeepAlive,{default:() => h(Component,{key:route.path})}) 
                        : h(Component,{key:route.path}) 
                    : ''
            })}
))

const DO:RouterOptions = {routes:[],history: createMemoryHistory()};

export class Router {
    constructor(options?:Partial<RouterOptions>){
        this.router = createRouter(Object.assign(DO,options || {}))

        this.router.beforeEach((to,from) => this.beforeEach(to,from))
        this.router.afterEach((to,from) => this.afterEach(to,from))
    }
    // 
    router:TypeRouter
    hooks = new Map<HookName,any[]>()
    //
    add(raw:RouteRecordRaw,parent?:any){
        if(parent){
            this.router.addRoute(parent,raw)
        }else{
            this.router.addRoute(raw)
        }
        return this;
    }
    remove(name:string){
        this.router.removeRoute(name)
        return this;
    }

    has(name:string){
        return this.router.hasRoute(name)
    }
    routes(){
        return this.router.getRoutes();
    }

    // 跳转
    go(delta:number){
        this.router.go(delta)
        return this;
    }
    refresh(useLocation:boolean){
        useLocation ? location.reload() : this.router.go(0)
        return this;
    }
    back(useHistory:boolean){
        useHistory ? history.back() : this.router.go(-1);
        return this;
    }
    forward(useHistory:boolean){
        useHistory ? history.forward() : this.router.go(1);
        return this;
    }

    
    // hooks
    addHook(name:HookName,f:(to:RouteLocationNormalizedGeneric,from:RouteLocationNormalizedGeneric) => any){
        if(!this.hooks.has(name)){
            this.hooks.set(name,[])
        }
        return this.hooks.get(name)?.push(f)
    }
    removeHook(name:HookName,index:number){
        // @ts-ignore
        if(this.hooks.has(name) && this.hooks.get(name).length > index){
            this.hooks.get(name)?.splice(index,1);
        }
    }
    clearHooks(name?:HookName){
        if(name && this.hooks.has(name)){
            // @ts-ignore
            this.hooks.get(name).length = 0;
        }
        else{
            this.hooks = new Map<HookName,any[]>()
        }
    }
    // 路由守卫
    async beforeEach(to:RouteLocationNormalizedGeneric,from:RouteLocationNormalizedGeneric){
        const hs = this.hooks.get('before');
        if(hs){
            for(const f of hs){
                let res:any;
                if(f.constructor.name == 'AsyncFunction'){
                    res = await f(to,from);
                }
                else{
                    res = f(to,from)
                }
                if(res != undefined){
                    return res;
                }
            }
        }
        return true;
    }
    async afterEach(to:RouteLocationNormalizedGeneric,from:RouteLocationNormalizedGeneric){
        const hs = this.hooks.get('after');
        if(hs){
            for(const f of hs){
                if(f.constructor.name == 'AsyncFunction'){
                    await f(to,from);
                }
                else{
                    f(to,from)
                }
            }
        }
    }

}

